/**
 * This is an example for the Newhaven NHD-3.12-25664UCY2 OLED based on SSD1322 drivers
 * The NHD-3.12-25664UCY2 is sold through Digikey and Mouser
 *
 * Following hardware connections are assumed
 *
 *   OLED                   Arduino 101
 *   ---------------------+------------------------------------------------------------------
 *   #1 Vss/GND             GND
 *   #2 Vdd                 3V3 (up to 271 mA, use external power supply to feed Arduino 101)
 *   #4 D/!C                D9
 *   #7 SCLK                D13 (hardware SPI SCLK)
 *   #8 SDIN                D11 (hardware SPI MOSI)
 *   #16 !RESET             !RESET
 *   #17 !CS                D10
 *   #5,#6,#10-14,#19,#20   GND
 *   #3,#9,#15,#18          not connected
 *
 * Based on Adafruit SSD1306 driver (https://github.com/adafruit/Adafruit_SSD1306)
 *   for which the original header is left below:
 */

/*********************************************************************
This is a library for the 256 x 64 pixel 16 color gray scale OLEDs
based on SSD1322 drivers

These displays use SPI to communicate, 4 or 5 pins are required to
interface

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada  for Adafruit Industries.
BSD license, check license.txt for more information
All text above, and the splash screen must be included in any redistribution
*********************************************************************/

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <ESP8266_SSD1322.h>

//ESP8266 Pins
//#define OLED_CS     15  // Pin 19, CS - Chip select
//#define OLED_DC     2   // Pin 20 - DC digital signal
//#define OLED_RESET  16  // Pin 15 -RESET digital signal

//Arduino_101 Pins
#define OLED_CS     10  // Pin 10, CS - Chip select
#define OLED_DC     9   // Pin 9 - DC digital signal
#define OLED_RESET  0   // using hardware !RESET from Arduino instead

// ATMega32u4 pins
//#define OLED_DC    8 //  D8  - B4
//#define OLED_CS    17 // D17 - B0
//#define OLED_RESET 9  // D9  - B5

//hardware SPI - only way to go. Can get 110 FPS
ESP8266_SSD1322 display(OLED_DC, OLED_RESET, OLED_CS);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

#if (SSD1322_LCDHEIGHT != 64)
#error("Height incorrect, please fix ESP8266_SSD1322.h!");
#endif

void setup()   {                
  Serial.begin(9600);
  
  // Initialize and perform reset
  oled.begin(true);
  // init done
  
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
    oled.oled();
    delay(2000);

  // Clear the buffer.
    oled.clearDisplay();

  // draw a single pixel
    oled.drawPixel(10, 10, WHITE);
  // Show the display buffer on the hardware.
  // NOTE: You _must_ call display after making any drawing commands
  // to make them visible on the display hardware!
    oled.oled();
    delay(2000);
    oled.clearDisplay();

  // draw many lines
    testdrawline();
    oled.oled();
    delay(2000);
    oled.clearDisplay();

  // draw rectangles
    testdrawrect();
    oled.oled();
    delay(2000);
    oled.clearDisplay();

  // draw multiple rectangles
    testfillrect();
    oled.oled();
    delay(2000);
    oled.clearDisplay();

    // draw mulitple circles
    testdrawcircle();
    oled.oled();
    delay(2000);
    oled.clearDisplay();

    // draw a white circle, 10 pixel radius
    oled.fillCircle(oled.width() / 2, oled.height() / 2, 10, WHITE);
    oled.oled();
    delay(2000);
    oled.clearDisplay();

    testdrawroundrect();
    delay(2000);
    oled.clearDisplay();

    testfillroundrect();
    delay(2000);
    oled.clearDisplay();

  testdrawtriangle();
    delay(2000);
    oled.clearDisplay();
   
  testfilltriangle();
    delay(2000);
    oled.clearDisplay();

  // draw the first ~12 characters in the font
    testdrawchar();
    oled.oled();
    delay(2000);
    oled.clearDisplay();

    // draw scrolling text
    testscrolltext();
    delay(2000);
    oled.clearDisplay();

    // text display tests
    oled.setTextSize(1);
    oled.setTextColor(WHITE);
    oled.setCursor(0, 0);
    oled.println("Hello, world!");
    oled.setTextColor(BLACK, WHITE); // 'inverted' text
    oled.println(3.141592);
    oled.setTextSize(2);
    oled.setTextColor(WHITE);
    oled.print("0x");
    oled.println(0xDEADBEEF, HEX);
    oled.oled();
    delay(2000);

    // miniature bitmap display
    oled.clearDisplay();
    oled.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1);
    oled.oled();

    // invert the display
    oled.invertDisplay(true);
    delay(1000);
    oled.invertDisplay(false);
    delay(1000);

    // draw a bitmap icon and 'animate' movement
    testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH);
}


void loop() {
  
}


void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  uint8_t icons[NUMFLAKES][3];
 
  // initialize
  for (uint8_t f=0; f< NUMFLAKES; f++) {
      icons[f][XPOS] = random(oled.width());
      icons[f][YPOS] = 0;
    icons[f][DELTAY] = random(5) + 1;
    
    Serial.print("x: ");
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(" y: ");
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(" dy: ");
    Serial.println(icons[f][DELTAY], DEC);
  }

  while (1) {
    // draw each icon
    for (uint8_t f=0; f< NUMFLAKES; f++) {
        oled.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE);
    }
      oled.oled();
      delay(200);
    
    // then erase it + move it
    for (uint8_t f=0; f< NUMFLAKES; f++) {
        oled.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK);
        // move it
        icons[f][YPOS] += icons[f][DELTAY];
        // if its gone, reinit
        if (icons[f][YPOS] > oled.height()) {
            icons[f][XPOS] = random(oled.width());
            icons[f][YPOS] = 0;
            icons[f][DELTAY] = random(5) + 1;
        }
    }
   }
}


void testdrawchar(void) {
    oled.setTextSize(1);
    oled.setTextColor(WHITE);
    oled.setCursor(0, 0);

    for (uint8_t i = 0; i < 168; i++) {
        if (i == '\n') continue;
        oled.write(i);
        if ((i > 0) && (i % 21 == 0))
            oled.println();
    }
    oled.oled();
}

void testdrawcircle(void) {
    for (int16_t i = 0; i < oled.height(); i += 2) {
        oled.drawCircle(oled.width() / 2, oled.height() / 2, i, WHITE);
        oled.oled();
    }
}

void testfillrect(void) {
  uint8_t color = 1;
    for (int16_t i = 0; i < oled.height() / 2; i += 3) {
        // alternate colors
        oled.fillRect(i, i, oled.width() - i * 2, oled.height() - i * 2, color % 2);
        oled.oled();
        color++;
    }
}

void testdrawtriangle(void) {
    for (int16_t i = 0; i < min(oled.width(), oled.height()) / 2; i += 5) {
        oled.drawTriangle(oled.width() / 2, oled.height() / 2 - i,
                          oled.width() / 2 - i, oled.height() / 2 + i,
                          oled.width() / 2 + i, oled.height() / 2 + i, WHITE);
        oled.oled();
    }
}

void testfilltriangle(void) {
    uint8_t color = WHITE;
    for (int16_t i = min(oled.width(), oled.height()) / 2; i > 0; i -= 5) {
        oled.fillTriangle(oled.width() / 2, oled.height() / 2 - i,
                          oled.width() / 2 - i, oled.height() / 2 + i,
                          oled.width() / 2 + i, oled.height() / 2 + i, WHITE);
        if (color == WHITE) color = BLACK;
        else color = WHITE;
        oled.oled();
    }
}

void testdrawroundrect(void) {
    for (int16_t i = 0; i < oled.height() / 2 - 2; i += 2) {
        oled.drawRoundRect(i, i, oled.width() - 2 * i, oled.height() - 2 * i, oled.height() / 4, WHITE);
        oled.oled();
    }
}

void testfillroundrect(void) {
    uint8_t color = WHITE;
    for (int16_t i = 0; i < oled.height() / 2 - 2; i += 2) {
        oled.fillRoundRect(i, i, oled.width() - 2 * i, oled.height() - 2 * i, oled.height() / 4, color);
        if (color == WHITE) color = BLACK;
        else color = WHITE;
        oled.oled();
    }
}
   
void testdrawrect(void) {
    for (int16_t i = 0; i < oled.height() / 2; i += 2) {
        oled.drawRect(i, i, oled.width() - 2 * i, oled.height() - 2 * i, WHITE);
        oled.oled();
    }
}

void testdrawline() {
    for (int16_t i = 0; i < oled.width(); i += 4) {
        oled.drawLine(0, 0, i, oled.height() - 1, WHITE);
        oled.oled();
    }
    for (int16_t i = 0; i < oled.height(); i += 4) {
        oled.drawLine(0, 0, oled.width() - 1, i, WHITE);
        oled.oled();
    }
    delay(250);

    oled.clearDisplay();
    for (int16_t i = 0; i < oled.width(); i += 4) {
        oled.drawLine(0, oled.height() - 1, i, 0, WHITE);
        oled.oled();
    }
    for (int16_t i = oled.height() - 1; i >= 0; i -= 4) {
        oled.drawLine(0, oled.height() - 1, oled.width() - 1, i, WHITE);
        oled.oled();
    }
    delay(250);

    oled.clearDisplay();
    for (int16_t i = oled.width() - 1; i >= 0; i -= 4) {
        oled.drawLine(oled.width() - 1, oled.height() - 1, i, 0, WHITE);
        oled.oled();
    }
    for (int16_t i = oled.height() - 1; i >= 0; i -= 4) {
        oled.drawLine(oled.width() - 1, oled.height() - 1, 0, i, WHITE);
        oled.oled();
    }
    delay(250);

    oled.clearDisplay();
    for (int16_t i = 0; i < oled.height(); i += 4) {
        oled.drawLine(oled.width() - 1, 0, 0, i, WHITE);
        oled.oled();
    }
    for (int16_t i = 0; i < oled.width(); i += 4) {
        oled.drawLine(oled.width() - 1, 0, i, oled.height() - 1, WHITE);
        oled.oled();
    }
    delay(250);
}

void testscrolltext(void) {
    oled.setTextSize(2);
    oled.setTextColor(WHITE);
    oled.setCursor(10, 0);
    oled.clearDisplay();
    oled.println("scroll");
    oled.oled();

    oled.startscrollright(0x00, 0x0F);
    delay(2000);
    oled.stopscroll();
    delay(1000);
    oled.startscrollleft(0x00, 0x0F);
    delay(2000);
    oled.stopscroll();
    delay(1000);
    oled.startscrolldiagright(0x00, 0x07);
    delay(2000);
    oled.startscrolldiagleft(0x00, 0x07);
    delay(2000);
    oled.stopscroll();
}

